﻿using BlazorAdmin.Interface;
using BlazorAdmin.Models;
using BlazorAdmin.Tcp.Server;
using BlazorAdmin.Web.Shared.Services;
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using NetTopologySuite.Index.HPRtree;
using Newtonsoft.Json;
using Pangeo.Admin.Interface.BussinessDb;
using Pangeo.Admin.Models;
using Pangeo.Admin.Models.ManageDb.Dto;
using System.IdentityModel.Tokens.Jwt;
using System.IO.Compression;
using System.Net.Mail;
using System.Security.Claims;
using System.Text;
using RouteAttribute = Microsoft.AspNetCore.Mvc.RouteAttribute;

namespace Pangeo.Admin.Web.Shared.Controllers
{
    /// <summary>
    /// 通用更新平台接口
    /// </summary>
    [Route("/Api")]
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    [Authorize(Roles = "BA")]
    [AllowAnonymous]
    public class ApiController : ControllerBase
    {
        private readonly ILog? LogSvr;
        private readonly ISettings? SettingSvr;
        private readonly IDevice? DeviceSvr;
        private readonly IEmailTasks EmailSvr;
        private readonly IQrqc QrqcSvr;
        private readonly TcpServer<DeviceTcpToken>? TcpServer;
        private readonly JsonSerializerSettings jsonSettings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore };

        public ApiController(ILog log, ISettings settings, IDevice device, IEmailTasks emailSvr, IQrqc qrqc, TcpServer<DeviceTcpToken> tcpServer)
        {
            LogSvr = log;
            SettingSvr = settings;
            DeviceSvr = device;
            TcpServer = tcpServer;
            EmailSvr = emailSvr;
            QrqcSvr = qrqc;
        }

        /// <summary>
        /// 获取Token认证接口
        /// </summary>
        /// <param name="user">账号</param>
        /// <param name="pwd">密码</param>
        /// <returns>签发的令牌</returns>
        /// <remarks>
        /// ```
        /// 注意：调用Api请将获取的Token放入请求头Authorization中
        /// </remarks>
        [AllowAnonymous]
        [HttpGet("Token")]
        public async Task<TokenResult> GetToken(string user, string pwd)
        {
            _ = Task.Run(async () => LogSvr.OperateLog(new()
            {
                RequestUser = user,
                RequestUrl = HttpContext.Request.Path.Value,
                RequestMethod = HttpContext.Request.Method,
                RequestData = "{ user: '" + user + "', pwd : '******' }",
                RequestProtocol = HttpContext.Request.Protocol,
                BizID = "获取Token",
                ClientIP = HttpContext.Connection?.RemoteIpAddress?.MapToIPv4().ToString(),
                UserAgent = HttpContext.Request.Headers["User-Agent"].ToString()
            }));

            var res = new TokenResult();
            if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(pwd))
            {
                res.Message = "用户名或密码不能为空！";
                return res;
            }

            var apiAcct = await SettingSvr?.GetApiAccount(user);
            if (apiAcct == null || apiAcct.Password != pwd)
            {
                res.Message = "用户名或密码不正确！";
                return res;
            }

            //定义许多种的声明Claim，信息存储部分，Claims的实体一般包含用户和一些元数据
            IEnumerable<Claim> claims = new Claim[]
            {
                new Claim("Id",Guid.NewGuid().ToString("D")),
                new Claim("Name", apiAcct.User),
                new Claim(ClaimTypes.Role, "BA")
            };

            var effective = DateTime.UtcNow; //生效时间 
            var expired = DateTime.UtcNow.AddDays(apiAcct.ExpireDays); //过期时间

            //Signing Credentials 签名凭证
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(BootstrapAppContext.JWT_SecurityKey));
            var signcreds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var jwtToken = new JwtSecurityToken("Hrm.Admin", "Hrm.Admin", claims, effective, expired, signcreds);
            var JwtHander = new JwtSecurityTokenHandler();
            var token = JwtHander.WriteToken(jwtToken);

            res.Success = true;
            res.Token = "Bearer " + token;
            res.ExpireTime = expired.ToString("yyyy-MM-dd HH:mm:ss");

            return res;
        }

        /// <summary>
        /// 文件备份接口
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// ```
        ///  注意：上传文件Request请求头必须包含以下信息：
        ///  GUID '设备ID（32位）'
        /// </remarks>
        [HttpPost("Upload")]
        public async Task<string> Upload()
        {
            var guid = HttpContext.Request.Headers["Guid"].ToString();

            try
            {
                _ = Task.Run(async () => LogSvr.OperateLog(new()
                {
                    RequestUser = "Service",
                    RequestUrl = HttpContext.Request.Path.Value,
                    RequestMethod = HttpContext.Request.Method,
                    RequestData = "{" + $"Guid: {guid}, FileName: ZipFile, FileLength: {Request.ContentLength}" + "}",
                    RequestProtocol = HttpContext.Request.Protocol,
                    BizID = "设备文件备份",
                    ClientIP = HttpContext.Connection?.RemoteIpAddress?.MapToIPv4().ToString(),
                    UserAgent = HttpContext.Request.Headers["User-Agent"].ToString()
                }));

                int maxFileSize = 50; // 最大上传文件50MB
                if (Request.ContentLength > maxFileSize * 1024 * 1024)
                    return $"upload file max size {maxFileSize} mb";

                if (string.IsNullOrEmpty(guid))
                    return "request header not exist [Guid]";

                var savePath = $"{Consts.BackupFilesPath}/{guid}";
                if (!Directory.Exists(savePath)) // 检查设备GUID目录是否存在
                    Directory.CreateDirectory(savePath);

                var zipFilePath = $"{savePath}/{DateTime.Now.ToString("yyMMddHHmmss")}.zip";

                // 将压缩包保存至设备目录下
                using (var stream = new MemoryStream())
                {
                    await Request.Body.CopyToAsync(stream);
                    using (var fileStream = new FileStream(zipFilePath, FileMode.Create))
                    {
                        stream.Seek(0, SeekOrigin.Begin);
                        await stream.CopyToAsync(fileStream);
                    }
                }

                // 解压缩zip文件至当前目录
                using (ZipArchive archive = ZipFile.OpenRead(zipFilePath))
                {
                    foreach (ZipArchiveEntry entry in archive.Entries)
                    {
                        // 解压缩文件至GUID目录下
                        entry.ExtractToFile($"{savePath}", overwrite: true);
                    }
                }

                System.IO.File.Delete(zipFilePath); // 解压缩成功后删除压缩包
                return "OK";
            }
            catch (Exception ex)
            {
                _ = Task.Run(async () => LogSvr.OperateLog(new()
                {
                    RequestUser = "Service",
                    RequestUrl = HttpContext.Request.Path.Value,
                    RequestMethod = HttpContext.Request.Method,
                    RequestData = "Params: {" + $"Guid: {guid}, FileName: ZipFile, FileLength: {Request.ContentLength}" + "}\n" + ex.ToString(),
                    RequestProtocol = HttpContext.Request.Protocol,
                    BizID = "设备文件备份（错误）",
                    ClientIP = HttpContext.Connection?.RemoteIpAddress?.MapToIPv4().ToString(),
                    UserAgent = HttpContext.Request.Headers["User-Agent"].ToString()
                }));

                return ex.Message;
            }
        }

        [HttpPost("SendEmail")]
        public async Task<string> SendEmail(string subject, string html, bool? isSendSQE)
        {
            if (html == null)
                return "邮件内容不能为空";

            try
            {
                var task = new EmailTask();
                task.Sender = "Qrqc";
                task.Subject = subject;
                task.HtmlContent = html;

                var accountJson = await SettingSvr.GetSettingsVal(task.Sender);
                var emailConfig = JsonConvert.DeserializeObject<EmailConfig>(accountJson);
                if (emailConfig == null)
                {
                    throw new Exception($"不存在邮件发送者：{task.Sender}");
                }

                var message = new MailMessage();

                var allUsers = QrqcSvr.GetAllUsers();
                var usrList = allUsers.Where(t => !t.DeptName.Equals("采购部/SQE")).Select(t => t.Email).ToList(); // 接收
                var ccList = allUsers.Where(t => t.DeptName.Equals("采购部/SQE")).Select(t => t.Email).ToList(); // 抄送
                //var bccList = new List<string>() { }; // 密送

                usrList.ForEach(addr =>
                {
                    if (!string.IsNullOrEmpty(addr))
                        message.To.Add(addr);
                });
                ccList.ForEach(addr =>
                {
                    if (!string.IsNullOrEmpty(addr))
                        message.CC.Add(addr);
                });

                //if (bccList != null && bccList.Count > 0) // 密送
                //    bccList.ForEach(addr => { message.Bcc.Add(addr); });

                task.Recipient = string.Join(",", usrList);
                task.CarbonCopy = string.Join(",", ccList);
                await EmailSvr.Save(task);

                message.From = new MailAddress(emailConfig.Account, "QRQC经验管理系统", Encoding.UTF8);
                message.Subject = task.Subject;
                message.SubjectEncoding = Encoding.UTF8;
                message.Body = task.HtmlContent;
                message.BodyEncoding = Encoding.UTF8;
                message.IsBodyHtml = true;

                message.Priority = MailPriority.Normal;
                /*switch (priority)
                {
                    case 2:
                        message.Priority = MailPriority.High;
                        break;
                    case 1:
                        message.Priority = MailPriority.Low;
                        break;
                    default:
                        message.Priority = MailPriority.Normal;
                        break;
                }*/

                var client = new SmtpClient(emailConfig.Server);
                client.Credentials = new System.Net.NetworkCredential(emailConfig.Account, emailConfig.Password);
                client.Send(message);

                task.IsDelivery = true;
                await EmailSvr.Save(task);

                return "发送成功";
            }
            catch (Exception ex)
            {
                return "邮件发送失败！\n" + ex.ToString();
            }
        }
    }
}